
package org.openeai.lite.common.control;

import org.apache.log4j.Logger;
import org.mule.MuleServer;
import org.mule.api.MuleContext;
import org.mule.module.client.MuleClient;
import org.openeai.lite.common.exception.OpenEAIException;
import org.openeai.lite.common.util.Constants;


public class ESBController
{

    private static Logger log = Logger.getLogger(ESBController.class);

    private MuleServer muleServer;

    private MuleContext muleContext;

    private MuleClient muleClient;
    
    private String startupType;

    // run controller as singleton
    private static volatile ESBController instance;

    private static final Object instanceLock = new Object();

    private ESBController()
    {
    };

    /**
     * Get the {@link ESBController} singleton instance in a thread safe way
     * (Java 1.5+ !!!)
     * 
     * @return The {@link ESBController} singleton instance.
     */
    public static ESBController getInstance()
    {
        if (instance == null)
        {
            synchronized (instanceLock)
            {
                if (instance == null)
                {
                    log.info("Creating new ESB Controller instance");
                    instance = new ESBController();
                }
            }
        }

        return instance;
    }

    /*
     * Start Mule
     */
    public void start(String startupType, String configuration) throws OpenEAIException
    {
        this.startupType = startupType;
        try
        {
            muleServer = new MuleServer();
            if (!isStarted())
            {
                if (startupType == null || startupType.equals(Constants.STARTUP_NORMAL))
                {
                    //We need to do this, as the conditional rendering of
                    //items in esb.xhtml depends on it.
                    this.startupType = Constants.STARTUP_NORMAL;
                    
                    log.info("Mule pre-flight check: dependencies");
                    checkAndLoadDepedencies();

                    log.info("Mule configuration set to " + Constants.MULE_CONFIG_DEFAULT);
                    muleServer.setConfigurationResources(Constants.MULE_CONFIG_DEFAULT);
                }
                else if (startupType.equals(Constants.STARTUP_CUSTOM) && configuration != null)
                {
                    log.info("Mule config file set to " + configuration);
                    muleServer.setConfigurationResources(configuration);
                }
                else
                {
                    throw new OpenEAIException("Error starting ESB with startup type "
                                    + startupType + " and optional configuration " + configuration);
                }

                
                log.info("Starting Mule server instance");
                muleServer.start(false, true);
                
                log.info("Retreiving Mule context.");
                muleContext = muleServer.getMuleContext();
            }
            else
            {
                log.info("ESB already started.");
            }
        }
        catch (Exception e)
        {
            log.error("Error starting ESB: " + e.getMessage());
            throw new OpenEAIException("Error starting ESB", e);
        }
    }

    /*
     * Stop Mule
     */
    public void stop() throws OpenEAIException
    {
        try
        {
            if (isStarted())
            {
                log.info("Shutting down ESB server instance...");
                muleServer.getMuleContext().stop();
                muleServer.getMuleContext().dispose();
                muleServer = null;
                log.info("ESB has been stopped.");
            }
            else
            {
                log.info("ESB is already stopped.");
            }
        }
        catch (Exception e)
        {
            log.error("Error stopping ESB");
            throw new OpenEAIException(e);
        }
    }

    /*
     * Check if Mule is started/active
     */
    public boolean isStarted()
    {
        try
        {
            if (this.muleContext != null)
            {
                return muleContext.isStarted();
            }
            else
            {
                return false;
            }
        }
        catch (Exception e)
        {
            return false;
        }
    }


    public String getStartupType()
    {
        return this.startupType;
    }

    
    public MuleContext getContext() throws OpenEAIException
    {
        try
        {
            return this.muleContext;
        }
        catch (Exception e)
        {
            log.error("Error getting Mule context!");
            throw new OpenEAIException(e);
        }
    }

    public MuleClient getClient() throws OpenEAIException
    {
        try
        {
            if (muleClient == null)
            {
                return new MuleClient(this.muleContext);
            }
            else
            {
                return this.muleClient;
            }
        }
        catch (Exception e)
        {
            log.error("Error getting Mule client!");
            throw new OpenEAIException(e);
        }
    }

    private void checkAndLoadDepedencies() throws OpenEAIException
    {
        log.info("Checking for dependencies.");
        try
        {
            String dep = ConfigController.getInstance().getProperty("mule.activemq.required");
            log.info("Message Broker required? : " + dep);
            if (dep.equals("true"))
            {
                // BrokerController has built-in check if it's already started.
                BrokerController.getInstance().start(null, null);
            }
        }
        catch (Exception e)
        {
            log.error("Error creating new Mule client!");
            throw new OpenEAIException(e);
        }
    }

}
